#include <unistd.h>
#include "bsp_radio_tx.h"
#include "elog.h"
#include "board.h"
#include "spi.h"

// #define LOG_TAG "bsp-radio-rx"
static lmx2572_handle_t tx_dev = NULL;
static uint8_t bsp_tx_init_state = 0;

// static void adc_init(void);
static uint8_t radio_tx_set_freq(lmx2572_handle_t dev, double Freq); // 接收本振频率（二阶）

// 10 3.7us,  100 26us, 4000 1ms
static void bsp_delay_ns(unsigned int xns)
{
    unsigned int i, j;
    for (i = 0; i < xns; i++)
    {
        for (j = 0; j < 1; j++)
            ;
    }
}

static const lmx2575_reg_value_table_t txpll_reg_table[] = {
    /* OUTB：Powerdown */
    /* default：OUTA：Freq 4855(VCO)  OUTB:Powerdown */
    {0x00, 0x201C},
    {0x05, 0x28C8},   /* R5, 之前为 0x05, 0x20C8, */
    {0x07, 0x40B2},   /* R7 */
                      /* 0x08, 0x6800 */
    {0x09, 0x1004},   /* R9 */
    {0x0A, 0x10F8},   /* R10  MULT  11-7(1) */
#if CONFIG_XTAL == 40 /* 40M */
    {0x0B, 0xB038},
#elif CONFIG_XTAL == 26 /* 26M */
    {0x0B, 0xB028},
#elif CONFIG_XTAL == 24 /*24.576 */
    {0x0B, 0xB018}, /* R11 PLL_R =  11-4bit (2) 24.576M 晶振 Fpd = 12.888MHZ */
#endif
    {0x0C, 0x5001}, /* R12  Pre-R  11-0(1) */
    {0x0E, 0x1878}, /* R14  泵电流配置最大 */
                    /* 0x10, 0x00BE */
    {0x11, 0x00BA}, /* R17 VCO_DACISET_STRT Starting calibration value for VCO_DACISET */
                    /* 0x13, 0x2773 */
    {0x14, 0x2048}, /* R20 select VCO4(4650-5200MHz,50-70V) */
    {0x1D, 0x18C6}, /* R29 */
    {0x1E, 0x18C6}, /* R30 */
    {0x22, 0x0010}, /* R34 PLL_N */
    {0x24, 0x01E5}, /* R36 PLL_N */
    {0x25, 0x0205}, /* R37 MASH_SEED_EN,PFD_DLY_SEL */
    {0x26, 0xFFFF}, /* R38 PLL_DEN */
    {0x27, 0xFFFF}, /* R39 PLL_DEN */
    {0x2A, 0x7FFF}, /* R42 PLL_NUM */
    {0x2B, 0xFFFF}, /* R43 PLL_NUM */
    {0x2C, 0x1F22}, /* R44 */
    {0x2D, 0xCE28}, /* R45 */
    {0x2E, 0x07F1}, /* R46 */
    {0x39, 0x0020}, /* R57 */
    {0x3A, 0x8001}, /* R58 */
    {0x3B, 0x0001}, /* R59 LD_TYPE */
    {0x3C, 0x03E8}, /* R60 */
    {0x3E, 0x00AF}, /* R62 */
    {0x45, 0x0000}, /* R69 */
    {0x46, 0xC350}, /* R70 */
    {0x47, 0x0080}, /* R71 */
    {0x48, 0x0001}, /* R72 */
    {0x49, 0x003F}, /* R73 */
    {0x4A, 0x0000}, /* R74 */
    {0x4B, 0x0800}, /* R75 输出分频数(2分频) */
    {0x4E, 0x00BF}, /* R78 VCO_CAPCTRL_STRT 参考8.14  select Partial Assist */
    {0x4F, 0x0000}, /* R79 */
    {0x50, 0x0000}, /* R80 */
    {0x51, 0x0000}, /* R81 */
    {0x52, 0x0000}, /* R82 */
    {0x53, 0x0000}, /* R83 */
    {0x54, 0x0000}, /* R84 */
    {0x55, 0x0000}, /* R85 */
    {0x56, 0x0000}, /* R86 */
    {0x60, 0x0000}, /* R96 */
    {0x61, 0x0000}, /* R97 */
    {0x62, 0x0000}, /* R98 */
    {0x63, 0x0000}, /* R99 */
    {0x64, 0x0000}, /* R100 */
    {0x65, 0x0000}, /* R101 */
    {0x66, 0x0000}, /* R102 */
    {0x67, 0x0000}, /* R103 */
    {0x68, 0x0000}, /* R104 */
    {0x69, 0x4440}, /* R105 */
    {0x6A, 0x0007}, /* R106 */
    {0x72, 0x7800}, /* R114 */
    {0x73, 0x0000}, /* R115 */
    {0x74, 0x0000}, /* R116 */
    {0x75, 0x0000}, /* R117 */
    {0x76, 0x0000}, /* R118 */
    {0x77, 0x0000}, /* R119 */
    {0x78, 0x0000}, /* R120 */
    {0x79, 0x0000}, /* R121 */
    {0x7A, 0x0000}, /* R122 */
    {0x7B, 0x0000}, /* R123 */
    {0x7C, 0x0000}, /* R124 */
};

// 分频系数表
static const lmx2575_frequency_table_tx_t rx_frequency_table[] =
    {
        {1600, 3200, 2, 0},
        {800, 1600, 4, 1},
        {400, 800, 8, 3},
        {200, 400, 16, 5},
        {100, 200, 32, 7},
        {50, 100, 64, 9},
        {25, 50, 128, 12},
        {12.5, 25, 256, 14},
};

/* 设置分频系数 */
static double bsp_radio_rx_frequency(lmx2572_handle_t dev, double Freq)
{
    uint16_t R75_Value = 0;
    uint16_t R75_Value_Read = 0;
    uint16_t reg_value = 0;
    uint16_t frequency_coefficient = 0;
    double freq_doubling;

    if (Freq > 3200 || Freq < 12.5)
    {
        printf("Freq > 3200 || Freq < 12.5 : %f \r\n", Freq);
        printf("bsp_radio_rx_frequency fail !!!\r\n");
        return 1;
    }

    for (uint8_t i = 0; i < (sizeof(rx_frequency_table) / sizeof(lmx2575_frequency_table_tx_t)); i++)
    {
        if (Freq > rx_frequency_table[i].freq_min)
        {
            reg_value = rx_frequency_table[i].reg_value;
            frequency_coefficient = rx_frequency_table[i].frequency_coefficient;
            // printf(" rx_frequency_table[i].reg_value : %d \r\n", reg_value);
            break;
        }
    }

    lmx2572_write_reg(dev, 0, 0x2018);          // ReadBack
    lmx2572_read_reg(dev, 75, &R75_Value_Read); //
    lmx2572_write_reg(dev, 0, 0x201C);          // LOCK
    // printf("\r\n R75_Value_Read :  0x%04x \r\n", R75_Value_Read);
    R75_Value_Read &= 0xF83F; // 将 10-6 位的值全部置零(将CHDIV位置0)

    R75_Value = R75_Value_Read + reg_value * 64;

    // printf("\r\n bsp_radio_rx_frequency :  0x%04x \r\n", R75_Value);
    lmx2572_write_reg(dev, 75, R75_Value);
    bsp_delay_ns(100);
    lmx2572_write_reg(dev, 0, 0x201C); // LOCK

    freq_doubling = frequency_coefficient * Freq;
    printf(" freq_doubling: %f = frequency_coefficient: %d * Freq : %f \r\n", freq_doubling, frequency_coefficient, Freq);

    return freq_doubling;
}

// 设置 通道A 直流通道或分频通道    value:0:分频 / value:1:直流 / value:3高阻
static uint8_t bsp_radio_rx_channel_a(lmx2572_handle_t dev, uint8_t value)
{
    static uint8_t channel_old = 255;
    uint16_t R45_Value = 0;
    uint16_t R45_Value_Read = 0;

    if (value > 3)
    {
        printf("bsp_radio_rx_channel_a fail ! \r\n");
    }

    //{0x2D, 0xCE28}, // R45 0xCE28 选择直通=0xCE28 或 分频=0xC628 高阻=0xDE28
    // if (channel_old == value)
    // {
    //     return 0;
    // }

    channel_old = value;

    lmx2572_write_reg(dev, 0, 0x2018);          // ReadBack
    lmx2572_read_reg(dev, 45, &R45_Value_Read); //
    lmx2572_write_reg(dev, 0, 0x201C);          // LOCK
    // printf("\r\n R45_Value_Read :  0x%04x \r\n", R45_Value_Read);
    R45_Value_Read &= 0xE7FF; // 将 12-11 位的值全部置零(将OUTA_MUX位置0)

    R45_Value = R45_Value_Read + value * 2048;
    //
    // printf("\r\n bsp_radio_rx_channel_a :  0x%04x \r\n", R45_Value);
    lmx2572_write_reg(dev, 45, R45_Value);
    bsp_delay_ns(100);
    lmx2572_write_reg(dev, 0, 0x201C); // LOCK
}

// 设置 通道B 直流通道或分频通道    value:0:分频 / value:1:直流 / value:2:系统 / value:3高阻
static uint8_t bsp_radio_rx_channel_b(lmx2572_handle_t dev, uint8_t value)
{
    static uint8_t channel_old = 255;
    uint16_t R46_Value = 0;
    uint16_t R46_Value_Read = 0;

    if (value > 3)
    {
        printf("bsp_radio_rx_channel_b fail ! \r\n");
    }

    // if (channel_old == value)
    // {
    //     return 0;
    // }

    channel_old = value;

    lmx2572_write_reg(dev, 0, 0x2018);          // ReadBack
    lmx2572_read_reg(dev, 46, &R46_Value_Read); //
    lmx2572_write_reg(dev, 0, 0x201C);          // LOCK
    // printf("\r\n R46_Value_Read :  0x%04x \r\n", R46_Value_Read);
    R46_Value_Read &= 0xFFFC; // 将 1-0 位的值全部置零(将OUTB_MUX位置0)

    R46_Value = R46_Value_Read + value;
    //
    // printf("\r\n bsp_radio_rx_channel_b :  0x%04x \r\n", R46_Value);
    lmx2572_write_reg(dev, 46, R46_Value);
    bsp_delay_ns(100);
    lmx2572_write_reg(dev, 0, 0x201C); // LOCK
}

/* 端口A使能 */
static uint8_t LO_RX_Switch_Port_A(lmx2572_handle_t dev, uint8_t ONorOFF) // 接收本振开关(二阶)
{
    uint16_t OUTA_PD = 0;
    uint16_t R44_Value = 0;
    uint16_t R44_Value_Read = 0;

    lmx2572_write_reg(dev, 0, 0x2018); // ReadBack
    // lmx2572_read_reg(dev, 44, &R44_Value_Read); //
    lmx2572_read_reg(dev, 44, &R44_Value_Read); //
    lmx2572_write_reg(dev, 0, 0x201C);          // LOCK

    R44_Value_Read &= 0xFFBF; // 取低16位的值(将OUTA_PD位置0)
    if (ONorOFF == 0)
    {
        OUTA_PD = 1; // 使能通道A， 1为关闭
    }
    else if (ONorOFF == 1)
    {
        OUTA_PD = 0; // 使能通道A， 0为打开
    }
    R44_Value = R44_Value_Read + OUTA_PD * 64;
    //
    lmx2572_write_reg(dev, 44, R44_Value);
    bsp_delay_ns(100);
    lmx2572_write_reg(dev, 0, 0x201C); // LOCK
    return 0;
}
/* 端口B使能 */
static uint8_t LO_RX_Switch_Port_B(lmx2572_handle_t dev, uint8_t ONorOFF) // 接收本振开关(三阶)
{
    uint16_t OUTB_PD = 0;
    uint16_t R44_Value = 0;
    uint16_t R44_Value_Read = 0;

    lmx2572_write_reg(dev, 0, 0x2018); // ReadBack
    // lmx2572_read_reg(dev, 44, &R44_Value_Read);
    lmx2572_read_reg(dev, 44, &R44_Value_Read);
    lmx2572_write_reg(dev, 0, 0x201C); // LOCK

    R44_Value_Read &= 0xFF7F; // 取低16位的值(将OUTB_PD位置0)
    if (ONorOFF == 0)
    {
        OUTB_PD = 1; // 使能通道B， 1为关闭
    }
    else if (ONorOFF == 1)
    {
        OUTB_PD = 0; // 使能通道B， 0为打开
    }
    R44_Value = R44_Value_Read + OUTB_PD * 128;
    //
    lmx2572_write_reg(dev, 44, R44_Value);
    bsp_delay_ns(100);
    lmx2572_write_reg(dev, 0, 0x201C); // LOCK
    return 0;
}

/* 设置通道输出和功率 */
static int bsp_radio_rx_set_output(lmx2572_handle_t dev, uint8_t enableA, int powerA, uint8_t enableB /*= false*/, int powerB /*= 63*/)
{
    uint16_t R44_Value = 0;
    uint16_t R45_Value = 0;

    lmx2572_write_reg(dev, 0, 0x2018); // ReadBack
    lmx2572_read_reg(dev, 44, &R44_Value);
    lmx2572_read_reg(dev, 45, &R45_Value);
    lmx2572_write_reg(dev, 0, 0x201C); // LOCK

    powerA &= 0x3f;
    R44_Value = 0x22 | (powerA << 8);
    printf("set output powerA= %d\r\n", powerA);
    if (!enableA)
        R44_Value |= 0x40;
    if (!enableB)
        R44_Value |= 0x80;
    lmx2572_write_reg(dev, 44, R44_Value);

    R45_Value = (R45_Value & 0xFFC0) | (powerB & 0x3f);
    lmx2572_write_reg(dev, 45, R45_Value);
    bsp_delay_ns(100);
    lmx2572_write_reg(dev, 0, 0x201C); // LOCK
    return 0;
}

static uint8_t radio_tx_set_freq(lmx2572_handle_t dev, double Freq) // 接收本振频率（二阶）
{
    // uint16_t ERROR_Count = 0;
    uint16_t R34_Value = 0;
    uint16_t R36_Value = 0;
    uint16_t R38_Value = 0;
    uint16_t R39_Value = 0;
    uint16_t R42_Value = 0;
    uint16_t R43_Value = 0;
    uint16_t R17_Value = 0;
    uint16_t R78_Value = 0;
    //
    double PLL = 0.0;
    double PLL_NUM = 0.0;
    uint32_t PLL_NUM_HL = 0;
    double PLL_dut = 0;
    double VCO_DACISET = 0;
    double VCO_CAPCTRL = 0;
    uint16_t PLL_N = 0;
    uint8_t VCOX = 3; // VCO4

    if (bsp_tx_init_state == 1 || dev == NULL)
    {
        return 1;
    }

    if (Freq < 12.5 || Freq > 6400)
    {
        printf("Freq < 12.5 || Freq > 6400, Freq: %f \r\n", Freq);
        printf("radio_rx_set_freq fail !!!\r\n");
        return 1;
    }
    else if (Freq >= 3200)
    {
        /* 设置直流通道 */
        bsp_radio_rx_channel_a(dev, 1);
        bsp_radio_rx_channel_b(dev, 1);
        // printf(" bsp_radio_rx_channel_a(dev, 1); \r\n");
    }
    else
    {
        /* 设置分频通道 */
        bsp_radio_rx_channel_a(dev, 0);
        bsp_radio_rx_channel_b(dev, 0);
        Freq = bsp_radio_rx_frequency(dev, Freq);
        // printf(" bsp_radio_rx_channel_a(dev, 0); \r\n");
    }

    // Freq  判断值的正确性(频率范围)
    if (Freq >= 3200 && Freq <= 3650)
    {
        VCOX = 0;
    }
    else if (Freq > 3650 && Freq <= 4200)
    {
        VCOX = 1;
    }
    else if (Freq > 4200 && Freq <= 4650)
    {
        VCOX = 2;
    }
    else if (Freq > 4650 && Freq <= 5200)
    {
        VCOX = 3;
    }
    else if (Freq > 5200 && Freq <= 5750)
    {
        VCOX = 4;
    }
    else if (Freq > 5750 && Freq <= 6400)
    {
        VCOX = 5;
    }
    else
    {
        printf("Freq : %f \r\n", Freq);
        printf("radio_tx_set_freq fail !!!\r\n");
        return 1; /* error */
    }

    // 配置R34,R36  PLL_N
    R34_Value = 0x0010;
    // #if 0 //40M
    // PLL = Freq / 10.0;
    // #else  //26M
    // PLL = Freq / 13.0;
    // #endif
#if CONFIG_XTAL == 40 // 40M
    PLL = Freq / (40.0 / 3.0);
#elif CONFIG_XTAL == 26 // 26M
    PLL = Freq / 13.0;
#elif CONFIG_XTAL == 24 // 24.576M
    PLL = Freq / (24.576 * 2.0);
#endif

    PLL_N = (int)PLL;
    // log_i("PLL_N=%d\n", PLL_N);
    R36_Value = PLL_N;
    // 配置R38,R39  PLL_DEN
    R38_Value = 0xFFFF;
    R39_Value = 0xFFFF;
    // 配置R42,R43  PLL_NUM
    PLL_NUM = PLL - PLL_N;
    PLL_dut = PLL_NUM * 0xFFFFFFFF;
    // log_i("PLL_NUM=%f PLL_dut=%f\n", PLL_NUM, PLL_dut);

    PLL_NUM_HL = (uint32_t)PLL_dut;
    // log_i("PLL_NUM_HL=0x%x\n",  PLL_NUM_HL);

    R42_Value = PLL_NUM_HL >> 16;
    R43_Value = PLL_NUM_HL & 0xFFFF;
    // 配置R17  VCO_DACISET_STRT
    //  VCO_DACISET_STRT = Round[A Min – (f VCO – f Min ) x (A Min – A Max ) / (f Max – f Min )] //{4650,  5200, 136,  25,   195,  172},   //VCO4
    VCO_DACISET = vcox[VCOX][4] - ((Freq - vcox[VCOX][0]) * (vcox[VCOX][4] - vcox[VCOX][5]) / (vcox[VCOX][1] - vcox[VCOX][0]));
    if (VCO_DACISET > (int)VCO_DACISET + 0.5)
    {
        R17_Value = (int)VCO_DACISET + 1;
    }
    else
    {
        R17_Value = (int)VCO_DACISET;
    }
    // 配置R78  VCO_CAPCTRL_STRT
    //  VCO_CAPCTRL_STRT = Round[C Min – (f VCO – f Min ) x (C Min – C Max ) / (f Max – f Min )] //{4650,  5200, 136,  25,   195,  172},   //VCO4
    VCO_CAPCTRL = vcox[VCOX][2] - ((Freq - vcox[VCOX][0]) * (vcox[VCOX][2] - vcox[VCOX][3]) / (vcox[VCOX][1] - vcox[VCOX][0]));
    if (VCO_CAPCTRL > (int)VCO_CAPCTRL + 0.5)
    {
        VCO_CAPCTRL = (int)VCO_CAPCTRL + 1;
    }
    else
    {
        VCO_CAPCTRL = (int)VCO_CAPCTRL;
    }
    R78_Value = VCO_CAPCTRL * 2 + 1;
    //
    lmx2572_write_reg(dev, 20, 0x2048); // R20_VALUE
    lmx2572_write_reg(dev, 34, R34_Value);
    lmx2572_write_reg(dev, 36, R36_Value);
    lmx2572_write_reg(dev, 38, R38_Value);
    lmx2572_write_reg(dev, 39, R39_Value);
    lmx2572_write_reg(dev, 42, R42_Value);
    lmx2572_write_reg(dev, 43, R43_Value);
    lmx2572_write_reg(dev, 17, R17_Value);
    lmx2572_write_reg(dev, 78, R78_Value);
    bsp_delay_ns(100);
    // LO_RX_Switch_Port_A(dev, 1);
    // LO_RX_Switch_Port_B(dev, 0);
    lmx2572_write_reg(dev, 0, 0x201C); // LOCK

    bsp_delay_ns(100);
    //    ERROR_Count = LO_RX_DC_GET();
    //	while (1 != LO_RX_DC_GET())
    //	{
    //	    if (ERROR_Count++ >= 2000)
    //	    {
    //	        break;
    //	    }
    //	}
    return 0;
}

// 设置发射频率
uint8_t bsp_radio_tx_freq_set(double freq)
{
    double freq_temp = 0;

    freq_temp = freq + 0.024; // 2400
    radio_tx_set_freq(tx_dev, freq_temp);

    return 0;
}

uint8_t bsp_radio_tx_init(void)
{
    uint8_t ret = 0;
    double freq_tx = 0;

    freq_tx = 2450; // MHz

    /* 1. 本振初始化 */
    // tx
    log_i("lmx2572 tx init start\r\n");
    tx_dev = lmx2572_create(&hspi1, SPI1_CS_GPIO_Port, SPI1_CS_Pin);
    if (tx_dev == NULL)
    {
        log_e("lmx2572 create tx_dev failed\n");
        return 1;
    }

    // 软件复位
    lmx2572_write_reg(tx_dev, 0, 0x221E); // Reset

    // tx配置
    ret = bsp_radio_tx_pll_check();
    if (ret != 0)
    {
        bsp_tx_init_state = 1;
        log_e("lmx2572 tx init fail !!!\n");
    }
    else
    {
        bsp_delay_ns(100);
        ret = lmx2572_reg_init(tx_dev, txpll_reg_table);
        if (ret != 0)
        {
            log_e("lmx2575 reg tx_dev init failed\n");
        }

        bsp_radio_tx_freq_set(freq_tx);
        bsp_radio_rx_set_output(tx_dev, 1, 28, 1, 28);
        log_i("lmx2575 reg tx_dev init successful \n");
    }

    return ret;
}

// uint8_t bsp_radio_tx_reinit(void)
// {
//     lmx2572_reg_init(tx_dev, txpll_reg_table);
//     return 0;
// }

// 本振0寄存器PowerDown操作
void bsp_radio_tx_sleep_44(uint8_t ONorOFF)
{
    if (ONorOFF == 0)
    {
        lmx2572_write_reg(tx_dev, 44, 0x14E2);
        // lmx2572_write_reg(rx3_dev, 44, 0x14E2);
        // lmx2572_write_reg(tx_dev, 0, 0x201d);
        // lmx2572_write_reg(rx3_dev, 0, 0x201d);
        bsp_delay_ns(100);
    }
    else if (ONorOFF == 1)
    {
        lmx2572_write_reg(tx_dev, 44, 0x14A2); // 开2阶
        // lmx2572_write_reg(tx_dev, 0, 0x201c);
        bsp_delay_ns(100);
    }
    else if (ONorOFF == 2)
    {
        // lmx2572_write_reg(rx3_dev, 44, 0x14A2); // 开3阶
        // lmx2572_write_reg(rx3_dev, 0, 0x201c);
        bsp_delay_ns(100);
    }
    else if (ONorOFF == 3)
    {
        // lmx2572_write_reg(rx_dev, 44, 0x1422); //全开
        bsp_delay_ns(100);
    }
    else
    {
        lmx2572_write_reg(tx_dev, 44, 0x14E2); // LOCK  Normal
        // lmx2572_write_reg(rx3_dev, 44, 0x14E2); // LOCK  Normal
        bsp_delay_ns(100);
    }
}

void bsp_radio_tx_sleep_0(uint8_t ONorOFF)
{
    lmx2572_sleep(tx_dev, ONorOFF); // 1-on  0-off
    // lmx2572_sleep(rx3_dev, ONorOFF); // 1-on  0-off
}

uint8_t bsp_radio_tx_pll_check(void)
{
    uint8_t ret = 0;

    lmx2572_write_reg(tx_dev, 0, 0x2018); // ReadBack
    ret = lmx2572_check_self(tx_dev);
    lmx2572_write_reg(tx_dev, 0, 0x201C); // LOCK

    return ret;
}
